#include "rtda/heap/constant_pool.h"
#include "rtda/heap/cp_classref.h"
#include "rtda/heap/cp_fieldref.h"
#include "rtda/heap/cp_methodref.h"
#include "rtda/heap/cp_interface_methodref.h"

namespace jvm {
namespace heap {

ConstantPool::ConstantPool(std::shared_ptr<Class> pClass, const classfile::ConstantPool& cfCp) 
    : m_pClass(pClass) {
    
    size_t cpCount = cfCp.size();
    m_consts.resize(cpCount);
    
    for (size_t i = 1; i < cpCount; i++) {
        std::shared_ptr<classfile::ConstantInfo> pCpInfo = cfCp[i];
        if (!pCpInfo) continue;
        
        switch (pCpInfo->get_tag()) {
            case classfile::CONSTANT_TAG::INTEGER: {
                auto pIntInfo = dynamic_cast<std::shared_ptr<classfile::ConstantIntegerInfo>>(pCpInfo);
                m_consts[i] = std::make_shared<int32_t>(pIntInfo->get_value());
                break;
            }
            case classfile::CONSTANT_TAG::FLOAT: {
                auto pFloatInfo = dynamic_cast<std::shared_ptr<classfile::ConstantFloatInfo>>(pCpInfo);
                m_consts[i] = std::make_shared<float>(pFloatInfo->get_value());
                break;
            }
            case classfile::CONSTANT_TAG::LONG: {
                auto pLongInfo = dynamic_cast<std::shared_ptr<classfile::ConstantLongInfo>>(pCpInfo);
                m_consts[i] = std::make_shared<int64_t>(pLongInfo->get_value());
                i++; // Long takes two slots
                break;
            }
            case classfile::CONSTANT_TAG::DOUBLE: {
                auto pDoubleInfo = dynamic_cast<std::shared_ptr<classfile::ConstantDoubleInfo>>(pCpInfo);
                m_consts[i] = std::make_shared<double>(pDoubleInfo->get_value());
                i++; // Double takes two slots
                break;
            }
            case classfile::CONSTANT_TAG::STRING: {
                auto pStringInfo = dynamic_cast<std::shared_ptr<classfile::ConstantStringInfo>>(pCpInfo);
                m_consts[i] = std::make_shared<std::string>(pStringInfo->get_string());
                break;
            }
            case classfile::CONSTANT_TAG::CLASS: {
                auto pClassInfo = dynamic_cast<std::shared_ptr<classfile::ConstantClassInfo>>(pCpInfo);
                m_consts[i] = ClassRef::newClassRef(this, pClassInfo);
                break;
            }
            case classfile::CONSTANT_TAG::FIELDREF: {
                auto pFieldrefInfo = dynamic_cast<std::shared_ptr<classfile::ConstantFieldRefInfo>>(pCpInfo);
                m_consts[i] = FieldRef::newFieldRef(this, pFieldrefInfo);
                break;
            }
            case classfile::CONSTANT_TAG::METHODREF: {
                auto pMethodrefInfo = dynamic_cast<std::shared_ptr<classfile::ConstantMethodRefInfo>>(pCpInfo);
                m_consts[i] = MethodRef::newMethodRef(this, pMethodrefInfo);
                break;
            }
            case classfile::CONSTANT_TAG::INTERFACE_METHODREF: {
                auto pInterfaceMethodrefInfo = dynamic_cast<std::shared_ptr<classfile::ConstantInterfaceMethodRefInfo>>(pCpInfo);
                m_consts[i] = InterfaceMethodRef::newInterfaceMethodRef(this, pInterfaceMethodrefInfo);
                break;
            }
            default:
                // TODO: Handle other constant types
                break;
        }
    }
}

} // namespace heap
} // namespace jvm